package org.acghub.common;

import java.util.*;
import java.util.function.Function;

public final class StringUtils extends ObjectUtils {
    public static final String EMPTY_STRING = "";

    public static <S extends CharSequence> boolean isBlank(S value) {
        if (isEmpty(value)) {
            return true;
        }
        for (int i = 0, n = value.length(); i < n; i++) {
            if (!Character.isWhitespace(value.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    public static <S extends CharSequence> boolean isNotBlank(S value) {
        return !isBlank(value);
    }

    public static <S extends CharSequence> S defaultIfBlank(S value, S defaultValue) {
        return isBlank(value) ? defaultValue : value;
    }

    private static String trim0(String value, TrimMode mode) {
        if (Objects.isNull(value)) {
            return null;
        }
        int start = 0;
        int end = value.length() - 1;
        if (mode == TrimMode.LEFT || mode == TrimMode.ALL) {
            while (start <= end && Character.isWhitespace(value.charAt(start))) {
                start++;
            }
        }
        if (mode == TrimMode.RIGHT || mode == TrimMode.ALL) {
            while (start <= end && Character.isWhitespace(value.charAt(end))) {
                end--;
            }
        }
        return start <= end ? value.substring(start, end + 1) : EMPTY_STRING;
    }

    public static String ltrim(final String value) {
        return trim0(value, TrimMode.LEFT);
    }

    public static String rtrim(final String value) {
        return trim0(value, TrimMode.RIGHT);
    }

    public static String trim(final String value) {
        return trim0(value, TrimMode.ALL);
    }

    public static List<String> split(final String value, final String separator) {
        if (isEmpty(value)) {
            return Collections.emptyList();
        }
        return Arrays.asList(value.split(separator));
    }

    public static List<List<String>> split(final String value, final String firstSeparator, String secondSeparator) {
        if (isEmpty(value)) {
            return Collections.emptyList();
        }
        List<List<String>> list = new ArrayList<>();
        String[] firstSplit = value.split(firstSeparator);
        for (String s : firstSplit) {
            List<String> subList = split(s, secondSeparator);
            if (isNotEmpty(subList)) {
                list.add(subList);
            }
        }
        return list;
    }

    public static <K, V> Map<K, V> split2Map(final String value, final String firstSeparator, final String secondSeparator,
                                             Function<String, K> keyFunction, Function<String, V> valueFunction) {
        assertNonNull(value, "value");
        assertNonNull(firstSeparator, "firstSeparator");
        assertNonNull(secondSeparator, "secondSeparator");
        assertNonNull(keyFunction, "keyFunction");
        assertNonNull(valueFunction, "valueFunction");

        List<List<String>> lists = split(value, firstSeparator, secondSeparator);

        Map<K, V> map = new HashMap<>(lists.size());

        for (List<String> list : lists) {
            assertTrue(list.size() == 2, "size != 2, list: " + list);
            K k = keyFunction.apply(list.get(0));
            V v = valueFunction.apply(list.get(1));
            map.put(k, v);
        }
        return map;
    }

    public static Map<Integer, Integer> split2IntIntMap(final String value, final String firstSeparator,
                                                        final String secondSeparator) {
        return split2Map(value, firstSeparator, secondSeparator, Integer::parseInt, Integer::parseInt);
    }

    public enum TrimMode {
        LEFT, RIGHT, ALL
    }

}
